package fr.univnantes.lina.uima.mapper.annotation.located;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.Vector;
import org.apache.uima.UimaContext;
import org.apache.uima.analysis_component.JCasAnnotator_ImplBase;
import org.apache.uima.analysis_engine.AnalysisEngineProcessException;
import org.apache.uima.cas.AbstractCas;
import org.apache.uima.cas.CAS;
import org.apache.uima.cas.CASException;
import org.apache.uima.cas.FSIterator;
import org.apache.uima.cas.Type;
import org.apache.uima.cas.text.AnnotationIndex;
import org.apache.uima.examples.SourceDocumentInformation;
import org.apache.uima.jcas.JCas;
import org.apache.uima.jcas.tcas.Annotation;
import org.apache.uima.resource.ResourceInitializationException;
import org.apache.uima.resource.ResourceProcessException;
import org.apache.uima.util.CasToInlineXml;

import fr.univnantes.lina.java.util.DateUtilities;
import fr.univnantes.lina.uima.common.AnnotationCollectionUtils;
import fr.univnantes.lina.uima.common.AnnotationUtils;
import fr.univnantes.lina.uima.common.CommonAE;
import fr.univnantes.lina.uima.common.DocumentAnnotationUtils;
import fr.univnantes.lina.uima.common.JCasSofaViewUtils;
import fr.univnantes.lina.uima.common.UIMAUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;



/**
 * Load into the CAS, the sentence and the word annotations represented in WST format within a given view 
 * <p>
 * This AE takes two parameters:
 * <ul>
 * <li><code>InputView</code> - view where are defined the sentence and the word annotations. Optional, by default 
 * <code>_InitialView</code></li>
 * <li><code>SentenceType</code> - type name of the Sentence annotations to create for each text part separated by a newline character. Optional, by default <code>org.apache.uima.SentenceAnnotation</code></li>
 * <li><code>WordType</code> - type name of the Word annotations to create for each text part separated by a whitespace character. Optional, by default <code>org.apache.uima.TokenAnnotation</code></li>
 * </ul>
 * 
 * 
 */
public class AnnotationPatternMapperAE extends CommonAE {

	/*
	 * PARAMETERS NAMES
	 */
	/**
	 * Parameter name of the sentence type
	 */
	public static final String PARAM_SENTENCE_TYPE = "SentenceType";

	/**
	 * Parameter name of the word type 
	 */
	public static final String PARAM_WORD_TYPE = "WordType";

	/**
	 * Parameter name for creating sentences 
	 */
	public static final String PARAM_CREATE_SENTENCES = "CreateSentences";

	/**
	 * Parameter name for creating words 
	 */
	public static final String PARAM_CREATE_WORDS= "CreateWords";


	/*
	 * PARAMETERS DEFAULT VALUES
	 */
	/**
	 * Default value of the word type
	 */
	public static String DEFAULT_WORD_TYPE = "org.apache.uima.TokenAnnotation";

	/**
	 * Default value of the sentence type
	 */
	public static String DEFAULT_SENTENCE_TYPE = "org.apache.uima.SentenceAnnotation";

	/**
	 * Default sentence end character value
	 */
	public static String DEFAULT_SENTENCE_END_CHARACTER_VALUE =	"\n" ;

	/*
	 * LOCAL VARIABLES
	 */

	private String sentenceTypeName;
	private String wordTypeName;
	private Boolean createSentences ;
	private Boolean createWords ;

	/*
	 * Accessors
	 */


	/*
	 * Methods 
	 */

	/**
	 * Get the parameter values, setting the variables and checking the values 
	 */
	public void initialize(UimaContext aContext) throws ResourceInitializationException {

		// SUPER PARAMETER SETTINGS
		super.initialize(aContext);

		// CURRENT AE PARAMETER SETTINGS


		//try {
		//} catch (Exception e) {
		//	String errmsg = "!";
		//	throw new ResourceInitializationException(errmsg, new Object[] {});
		//}		
	}

	/**
	 * Based on the sentences and the words represented in WST format from a given view <br>
	 * Create the corresponding annotations into the CAS.
	 * 
	 * @return a null content
	 */
	@Override
	protected String processInputView(JCas inputViewJCas,
			FSIterator contextAnnotationsFSIter,
			HashMap<String, Integer> inputAnnotationStringHashMap,
			String inputFeatureString, JCas outputViewJCas,
			String outputAnnotationString, String ouputFeatureString)
					throws AnalysisEngineProcessException {

		//System.out.println("Debug: class>"+this.getClass().getName()+"< now>" + JavaUtilities.now());

		LocatedAnnotationIndex locatedAnnotationIndex = LocatedAnnotationIndexBuilder.buildsIndex(inputViewJCas);

		// data structures for testing or handling the index
		Map<String,LocatedAnnotation> locatedAnnotationMap = locatedAnnotationIndex.getLocatedAnnotationMap();
		Map<Integer,List<Annotation>> annotationBeginMap = locatedAnnotationIndex.getAnnotationBeginMap();
		Map<Integer,List<Annotation>> annotationEndMap = locatedAnnotationIndex.getAnnotationEndMap();
		Map<String,LocatedAnnotation> locatedAnnotationSortedMap = new TreeMap(locatedAnnotationMap);
		Map<Integer,List<Annotation>> annotationBeginSortedMap = new TreeMap(annotationBeginMap);
		Map<Integer,List<Annotation>> annotationEndSortedMap = new TreeMap(annotationEndMap);
		// Map = new TreeMap (Map) gives a sortedkey
		// TreeMap = new TreeMap (Map) gives access to the api of TreeMap

		Set<String> offsetSet = locatedAnnotationMap.keySet();
		Set<Integer> beginSet = annotationBeginMap.keySet();
		Set<Integer> endSet = annotationEndMap.keySet();
		Set<String> sortedOffsetSet = locatedAnnotationSortedMap.keySet();
		Set<Integer> sortedBeginSet = annotationBeginSortedMap.keySet();
		Set<Integer> sortedEndSet = annotationEndSortedMap.keySet();

		// -- test currentAnnotationList
		//testCurrentAnnotationList(locatedAnnotationMap, offsetSet);

		// -- test annotationBeginMap with and without sorting the keys
		// testAnnotationOffsetMap(annotationBeginMap, beginSet);
		// testAnnotationOffsetMap(annotationBeginMap, sortedBeginSet);

		// -- test annotationEndMap with and without sorting the keys
		// testAnnotationOffsetMap(annotationEndMap, endSet);
		// testAnnotationOffsetMap(annotationEndMap, sortedEndSet);

		// -- test LocatedAnnotation current AnnotationList 
		//testLocatedAnnotationAnnotationList(locatedAnnotationMap, offsetSet, "getCurrent");
		// -- test LocatedAnnotation next AnnotationList 
		//testLocatedAnnotationAnnotationList(locatedAnnotationMap, offsetSet, "getNext");

		// test LocatedAnnotation any AnnotationList 
		testLocatedAnnotationAnnotationList(locatedAnnotationMap, sortedOffsetSet);

		// return a default value, because required, but the outputview should not be used
		return inputViewJCas.getDocumentText();
	}


	/**
	 * testCurrentAnnotationList
	 */
	private final void testCurrentAnnotationList(
			Map<String, LocatedAnnotation> locatedAnnotationMap,
			Set<String> offsetSet) {
		for (String offset : offsetSet) {
			System.out.print("Debug: offset>"+offset+"< "); 
			LocatedAnnotation locatedAnnotation = (LocatedAnnotation) locatedAnnotationMap.get(offset);
			List<Annotation> currentAnnotationList = locatedAnnotation.getCurrent();
			for (Annotation annotation : currentAnnotationList) {
				System.out.print(">"+annotation.getType().getName()+"< ");
			}
			System.out.println("");
		}
	}

	/**
	 * Test LocatedAnnotation Vicinity AnnotationList
	 * @param locatedAnnotationMap
	 * @param offsetSet
	 * @param annotationListName
	 */
	private final void testLocatedAnnotationAnnotationList(
			Map<String, LocatedAnnotation> locatedAnnotationMap,
			Set<String> offsetSet,
			String annotationListName) {

		for (String offset : offsetSet) {
			System.out.print("Debug: "+annotationListName+" of the offset>"+offset+"<"); 
			LocatedAnnotation locatedAnnotation = (LocatedAnnotation) locatedAnnotationMap.get(offset);
			List<Annotation> givenAnnotationList = null;
			try {
				Method getMethod = locatedAnnotation.getClass().getMethod(annotationListName);
				givenAnnotationList = (List<Annotation>) getMethod.invoke(locatedAnnotation);
			} catch (SecurityException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (NoSuchMethodException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			for (Annotation annotation : givenAnnotationList) {
				System.out.print(">"+annotation.getType().getName()+"< ");
			}
			System.out.println("");
		}
	}

	/**
	 * Test LocatedAnnotation Vicinity AnnotationList
	 * @param locatedAnnotationMap
	 * @param offsetSet
	 * @param annotationListName
	 */
	private final void testLocatedAnnotationAnnotationList(
			Map<String, LocatedAnnotation> locatedAnnotationMap,
			Set<String> offsetSet) {

		for (String offset : offsetSet) {
			System.out.println("Debug: of the offset>"+offset+"<"); 
			LocatedAnnotation locatedAnnotation = (LocatedAnnotation) locatedAnnotationMap.get(offset);
			List<Annotation> givenAnnotationList = null;
//			String[] annotationListNames = {"getCurrent", "getNext", "getPartialNext" , "getPrevious", "getPartialPrevious", "getSuper", "getSub"};
			String[] annotationListNames = {"getCurrent", "getSuper", "getSub"}; //"getNext", "getPrevious", 
			try {
				for (String annotationListName : annotationListNames) {
					Method getMethod = locatedAnnotation.getClass().getMethod(annotationListName);
					givenAnnotationList = (List<Annotation>) getMethod.invoke(locatedAnnotation);
					System.out.println("\t >"+annotationListName+"<"); 
					for (Annotation annotation : givenAnnotationList) {
						System.out.println("\t\t >"+annotation.getType().getName()+":"+annotation.getCoveredText()+":"+annotation.getBegin()+":"+annotation.getEnd()+"<");
					}
					System.out.println();
				}

			} catch (SecurityException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (NoSuchMethodException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
	}

	/**
	 * testAnnotationBeginMap and testAnnotationEndMap
	 */
	private final void testAnnotationOffsetMap(
			Map<Integer, List<Annotation>> annotationOffsetMap, Set<Integer> offsetSet) {
		for (int offset : offsetSet) {
			System.out.print("Debug: offsetKey>"+offset+"< "); 
			List<Annotation> offsetAnnotationList = annotationOffsetMap.get(offset);
			for (Annotation annotation : offsetAnnotationList) {
				System.out.println("\tbegin>"+annotation.getBegin()+"< end>"+annotation.getEnd()+"< >"+annotation.getType().getName()+"< ");
			}
			System.out.println("");
		}
	}


}




